package com.it.service.impl;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.it.auth.LoginConvert;
import com.it.auth.LoginInfoDTO;
import com.it.auth.WxInfoDTO;
import com.it.bean.User;
import com.it.enums.WxGenderEnums;
import com.it.mapper.MenuMapper;
import com.it.mapper.UserMapper;
import com.it.service.LoginService;
import com.it.utils.AppUtils;
import com.it.vo.MenuVo;
import com.it.vo.RoleVo;
import com.it.vo.UserVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service("loginService")
@RequiredArgsConstructor
public class LoginServiceImpl implements LoginService {

    private final UserMapper userMapper;

    private final MenuMapper menuMapper;

    @Override
    public SaResult login(LoginInfoDTO loginInfoDTO) {
        Map<String, Object> dataMap = new HashMap<>();
        UserVo user = userMapper.findUser(loginInfoDTO);
        Objects.requireNonNull(user, "用户名或密码错误!");
        StpUtil.login(user.getId());
        String token = StpUtil.getTokenValue();
        SaSession session = StpUtil.getTokenSession();
        session.set("username", user.getUsername());
        session.set("currentUser", user);
        List<RoleVo> roles = user.getRoles();
        List<MenuVo> allMenus = new ArrayList<>();
        for (RoleVo role : roles) {
            List<MenuVo> menus = role.getMenus();
            if (menus != null) {
                allMenus.addAll(menus);
            }
        }
        List<Long> roleIds = roles.stream().map(RoleVo::getId).collect(Collectors.toList());
        List<Long> menuIds = allMenus.stream().map(MenuVo::getId).collect(Collectors.toList());
        List<MenuVo> permissions = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(roleIds) && CollectionUtil.isNotEmpty(menuIds)) {
            permissions = menuMapper.permissions(roleIds, menuIds);
        }
        dataMap.put("token", token);
        dataMap.put("roles", LoginConvert.toRoles(roles));
        dataMap.put("permissions", LoginConvert.toPermissions(permissions));
        dataMap.put("user", user);
        dataMap.put("expireAt", DateUtil.nextMonth().getTime());
        return SaResult.data(dataMap);
    }

    @Override
    public List<MenuVo> findAllRoutes(Long loginId) {
        LoginInfoDTO loginInfoDTO = new LoginInfoDTO();
        loginInfoDTO.setUserId(loginId);
        UserVo user = userMapper.findUser(loginInfoDTO);
        Objects.requireNonNull(user);
        List<MenuVo> allMenus = user.getRoles()
                .parallelStream()
                .map(RoleVo::getMenus)
                .filter(Objects::nonNull)
                .flatMap(List::stream)
                .sorted(Comparator.comparing(MenuVo::getSort))
                .collect(Collectors.toList());
        return AppUtils.buildMenuTree(allMenus);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SaResult wxLogin(LoginInfoDTO loginInfoDTO, WxInfoDTO wxInfoDTO) {
        User condition = new User();
        condition.setWxOpenId(loginInfoDTO.getWxOpenId());
        User user = userMapper.selectOne(condition);
        if (Objects.isNull(user)) {
            User wxUser = new User();
            wxUser.setWxOpenId(loginInfoDTO.getWxOpenId());
            wxUser.setName(wxInfoDTO.getNickName());
            wxUser.setSex(WxGenderEnums.getSex(wxInfoDTO.getGender()));
            wxUser.setAvatar(wxInfoDTO.getAvatarUrl());
            wxUser.setDeleted(false);
            wxUser.setUsername(IdUtil.simpleUUID());
            wxUser.setPassword(AppUtils.md5(loginInfoDTO.getWxOpenId()));
            userMapper.insert(wxUser);
        }
        return login(loginInfoDTO);
    }
}
